﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Input;

namespace Deflection
{
    class Player : GameObject
    {

        public static Texture2D PlayerSprite { get; set; }
        public static SoundEffect Shoot1 { get; set; }
        public static SoundEffect Shoot2 { get; set; }
        public static SoundEffect Shoot3 { get; set; }
        public float scale;
        public Score Score { get; set; }
        public bool touchingOtherPlayer;
        public enum PlayerState
        {
            Spawning,
            Alive,
            Dying,
            Dead,
            GameOver
        }

        /// <summary>
        /// The unique ID of the player
        /// </summary>
        public int PlayerID { get; set; }

        public PlayerState  playerState;

        public Vector2 velocity;



        public float timeTillNextShot;

        public int upKey, downKey, leftKey, rightKey, fireKey;
        public Color color;
        public ParticleSystem particleSystem;


        public int Lives { get; set; }
        public bool NoLivesLeft { get; set; }

        private CustomTimer spawnTimer { get; set; }

        public Player(Vector2 position) : base(position)
        {
            playerState = PlayerState.Alive;

        }

        public Player(int playerID, Vector2 Position)  : base(Position)
        {
            this.PlayerID = playerID;
            playerState = PlayerState.Alive;
            scale = 0.5f;
            touchingOtherPlayer = false;
            sizeInPixels = new Vector2(scale * Player.PlayerSprite.Bounds.Width,scale * Player.PlayerSprite.Bounds.Height);
            this.velocity = new Vector2(0.0f, 0.0f);
            this.timeTillNextShot = GameParameters.PLAYER_FIRE_INTERVAL;
            SetUpPlayer();
            particleSystem = new ParticleSystem(Position, Player.PlayerSprite, color, 0.15f);
            particleSystem.MaxLife = 40;
            particleSystem.Drawing = true;
            particleSystem.MaximumParticles = 5000;
            particleSystem.maxParticleVelocity = 2.0f;
            particleSystem.minParticleVelocity = -2.0f;
            particleSystem.SpawnRate = 0;

            // Lives

            Lives = GameParameters.PLAYER_STARTING_LIVES;
            NoLivesLeft = false;
            spawnTimer = new CustomTimer();
        }

        public void SetUpPlayer()
        {
            if (PlayerID == 1)
            {
                upKey = (int)Keys.W;
                downKey = (int)Keys.S;
                leftKey = (int)Keys.A;
                rightKey = (int)Keys.D;
                fireKey = (int)Keys.Space;
                color = new Color(191, 167, 219); // purple
                Score = new Score(GameParameters.PLAYER1_START_POSITION, color);
                
            }
            else if (PlayerID == 2)
            {
                upKey = (int)Keys.Up;
                downKey = (int)Keys.Down;
                leftKey = (int)Keys.Left;
                rightKey = (int)Keys.Right;
                fireKey = (int)Keys.RightShift;
                color = new Color(235, 95, 81); // redish
                Score = new Score(GameParameters.PLAYER2_START_POSITION + new Vector2(0, 50.0f), color);
            }
        }

        public void ResetPlayer()
        {

        }

        public override void Update(GameTime gameTime)
        {

            float elapsedTime = (float)gameTime.ElapsedGameTime.TotalSeconds;
            timeTillNextShot -= elapsedTime;
            #region pause

            if (InputHandler.IsKeyDown(Keys.Escape))
            {
                // Player wants to pause the game
                Game1.State = Game1.GameState.Pause;
            }

            #endregion pause

            switch (playerState)
            {
                case PlayerState.Spawning:

                    switch (PlayerID)
                    {
                        case 1:
                            Position = GameParameters.PLAYER1_START_POSITION;
                            break;
                        case 2:
                            Position = GameParameters.PLAYER2_START_POSITION;
                            break;
                        default:
                            break;
                          
                    }

                    spawnTimer.Start();
                    if (spawnTimer.Counter >= GameParameters.PLAYER_SPAWN_DELAY)
                    {
                        // Done spawning
                        IsCollidable = true;

                        spawnTimer.Stop();
                        spawnTimer.Reset();

                        // Reset particles
                        particleSystem.Spawning = true;

                        // Reset velocity
                        this.velocity = new Vector2(0.0f, 0.0f);

                        // reset Color
                        color.A = 255;

                        playerState = PlayerState.Alive;
                    }
                    else
                    {
                        // Do spawning stuff
                        IsCollidable = false;
                        Random rand = new Random();
                        color.A = (byte)rand.Next(100, 255);

                    }
                    

                    break;
                case PlayerState.Alive:

                    #region Firing

                    if (InputHandler.IsKeyDown((Keys)fireKey) && this.timeTillNextShot < 0)
                    {
                        Fire();
                        timeTillNextShot = GameParameters.PLAYER_FIRE_INTERVAL;
                        Score.ProjectilesFired++;
                        Random rand = new Random(gameTime.TotalGameTime.Milliseconds);
                        int r = rand.Next(0, 100);
                        if(r<=33)
                        {
                            Shoot1.Play(0.15f, 0.0f, 0.0f);
                        }
                        else if(r <= 66)
                        {
                            Shoot2.Play(0.15f, 0.0f, 0.0f);
                        }
                        else
                        {
                            Shoot3.Play(0.15f,0.0f,0.0f);
                        }
                    }

                    #endregion Firing

                    #region Movement

                    if (InputHandler.IsKeyDown((Keys)upKey))
                    {
                        if (this.position.Y > (PlayerSprite.Height / 4))
                        {
                            if (velocity.Y > -GameParameters.PLAYER_SPEED)
                            {
                                velocity.Y -= GameParameters.PLAYER_MOVEMENT_ACCELERATION;
                            }
                        }
                        else
                        {
                            velocity.Y = 0.0f;
                            this.position.Y = (PlayerSprite.Height / 4);
                        }
                    }
                    if (InputHandler.IsKeyDown((Keys)leftKey))
                    {
                        if(this.position.X > (PlayerSprite.Width / 4))
                        {
                            if (velocity.X > -GameParameters.PLAYER_SPEED)
                            {
                                velocity.X -= GameParameters.PLAYER_MOVEMENT_ACCELERATION;
                            }
                        }
                        else
                        {
                            velocity.X = 0.0f;
                            this.position.X = (PlayerSprite.Width / 4);
                        }
                    }
                    if (InputHandler.IsKeyDown((Keys)downKey))
                    {
                        if(this.position.Y < GameParameters.SCREEN_SIZE.Y - (PlayerSprite.Height / 4))
                        {
                            if (velocity.Y < GameParameters.PLAYER_SPEED)
                            {
                                velocity.Y += GameParameters.PLAYER_MOVEMENT_ACCELERATION;
                            }
                        }
                        else
                        {
                            velocity.Y = 0.0f;
                            this.position.Y = GameParameters.SCREEN_SIZE.Y - (PlayerSprite.Height / 4);
                        }
                    }
                    if (InputHandler.IsKeyDown((Keys)rightKey))
                    {
                        if (this.position.X < GameParameters.SCREEN_SIZE.X - (PlayerSprite.Width / 4))
                        {
                            if (velocity.X < GameParameters.PLAYER_SPEED)
                            {
                                velocity.X += GameParameters.PLAYER_MOVEMENT_ACCELERATION;
                            }
                        }
                        else
                        {
                            velocity.X = 0.0f;
                            this.position.X = GameParameters.SCREEN_SIZE.X - (PlayerSprite.Width / 4);
                        }
                    }

                    if (InputHandler.IsKeyUp((Keys)upKey) && velocity.Y < 0.0f)
                    {
                        if (this.position.Y < PlayerSprite.Height/4)
                        {
                            velocity.Y = 0.0f;
                        }
                        else if (0.0f - velocity.Y < GameParameters.PLAYER_MOVEMENT_DECELERATION)
                        {
                            velocity.Y = 0.0f;
                        }
                        else
                        {
                            velocity.Y += GameParameters.PLAYER_MOVEMENT_DECELERATION;
                        }
                    }
                    if (InputHandler.IsKeyUp((Keys)leftKey) && velocity.X < 0.0f)
                    {
                        if(this.position.X < 0.0f)
                        {
                            velocity.X = 0.0f;
                        }
                        else if (0.0f - velocity.X < GameParameters.PLAYER_MOVEMENT_DECELERATION)
                        {
                            velocity.X = 0.0f;
                        }
                        else
                        {
                            velocity.X += GameParameters.PLAYER_MOVEMENT_DECELERATION;
                        }
                    }
                    if (InputHandler.IsKeyUp((Keys)downKey) && velocity.Y > 0.0f)
                    {
                        if (this.position.Y > GameParameters.SCREEN_SIZE.Y - PlayerSprite.Height / 4)
                        {
                            velocity.Y = 0.0f;
                        }
                        else
                        {
                            velocity.Y -= GameParameters.PLAYER_MOVEMENT_DECELERATION;
                        }
                    }
                    if (InputHandler.IsKeyUp((Keys)rightKey) && velocity.X > 0.0f)
                    {
                        if (this.position.X > GameParameters.SCREEN_SIZE.X)
                        {
                            velocity.X = 0.0f;
                        }
                        else
                        {
                            velocity.X -= GameParameters.PLAYER_MOVEMENT_DECELERATION;
                        }
                    }
                    position += velocity;

                    #endregion Movement
                    particleSystem.Position = this.position;
                    particleSystem.Update(gameTime);
                    break;
                case PlayerState.Dying:
                    if (particleSystem.Particles.Count > 0)
                    {
                        particleSystem.Spawning = false;
                        particleSystem.Position = this.position;
                        particleSystem.Update(gameTime);
                    }
                    else
                    {
                        playerState = PlayerState.Dead;
                    }
                    break;
                case PlayerState.Dead:
                    // Call Die to removes lives and check if it should respawn
                    Die();

                    break;

                case PlayerState.GameOver:
                    break;
                default:
                    break;
            }
            if (PlayerFactory.Instance().Players.Count > 1)
            {
                foreach(Player p in PlayerFactory.Instance().Players)
                {
                    if(p != this)
                    {
                        if (GetDistance(p.position) < this.sizeInPixels.X * 95/100)
                        {
                            Vector2 dir = new Vector2();
                            dir = this.position - p.position;
                            dir.Normalize();
                            dir = dir * GameParameters.PLAYER_SPEED/10;
                            this.position += dir;
                        }
                    }
                }
            }
        }
        
        public override void Draw(GameTime gameTime, SpriteBatch spriteBatch)
        {
            switch (playerState)
            {
                case PlayerState.Spawning:
                    spriteBatch.Draw(Player.PlayerSprite, position, null, color, 0, new Vector2(Player.PlayerSprite.Bounds.Center.X, Player.PlayerSprite.Bounds.Center.Y), scale, SpriteEffects.None, 0);
                    break;

                case PlayerState.Alive:
                    spriteBatch.Draw(Player.PlayerSprite, position, null, color, 0, new Vector2(Player.PlayerSprite.Bounds.Center.X, Player.PlayerSprite.Bounds.Center.Y), scale, SpriteEffects.None, 0);
                    if (particleSystem.Texture != null)
                    {
                        particleSystem.Draw(gameTime, spriteBatch);
                    }
                break;
                case PlayerState.Dying:
                    if (particleSystem.Texture != null && particleSystem.Particles.Count > 0)
                    {
                        particleSystem.Draw(gameTime, spriteBatch);
                    }

                break;
                case PlayerState.Dead:

                break;

                case PlayerState.GameOver:

                break;

                default:
                break;
            }
            Score.Draw(spriteBatch);
        }

        public void Fire()
        {
            ProjectileFactory.CreateProjectile(this.Position, Projectile.ProjectileType.PlayerBasicProjectile, new Vector2(0.2f, 0.0f), this.color, this);
        }

        public override void Die()
        {
            // take away 1 life
            Lives--;
            // Check if the player has any lives left to carry on playing
            if (CheckIfLivesLeft())
            {
                // Player can carry on player, set the player to respawming
                playerState =  PlayerState.Spawning;
            }
            else
            {
                // Player has no lives so its game over for him
                Lives = 0;
                NoLivesLeft = true;
                playerState = PlayerState.GameOver;
            }


            //base.Die();
            
        }

        public bool CheckIfLivesLeft()
        {
            return Lives > 0;
        }

    }
}
